package com.reverie.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.db.sql.Order;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.reverie.common.pojo.CommonPageReq;
import com.reverie.config.CommonException;
import com.reverie.config.DateTimeFormatterConstants;
import com.reverie.config.util.DateUtils;
import com.reverie.dto.req.ChartParam;
import com.reverie.dto.req.DisShippingParam;
import com.reverie.dto.req.MakeQueryParam;
import com.reverie.dto.req.OrderQueryParam;
import com.reverie.dto.resp.AnalysisData;
import com.reverie.dto.resp.GoodAttrCountData;
import com.reverie.dto.resp.StatisticModel;
import com.reverie.entity.*;
import com.reverie.mapper.OrderInfoMapper;
import com.reverie.plugins.gaode.client.GaoDeClient;
import com.reverie.plugins.gaode.dto.GaoDeResponse;
import com.reverie.service.*;
import com.reverie.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Rui.Zhou
 * @since 2024-02-03
 */
@Service
@Slf4j
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements IOrderInfoService {

    private final IMemberService memberService;
    private final IOrderGoodsService orderGoodService;
    private final IGoodsService goodsService;
    private final IShopperService shopperService;
    private final IRegionService regionService;
    private final ICouponService couponService;
    private final ICouponLogService couponLogService;

    private final OrderInfoMapper orderInfoMapper;

    public OrderInfoServiceImpl(IMemberService memberService, IOrderGoodsService orderGoodService, IGoodsService goodsService, IShopperService shopperService, IRegionService regionService, ICouponService couponService, ICouponLogService couponLogService, OrderInfoMapper orderInfoMapper) {
        this.memberService = memberService;
        this.orderGoodService = orderGoodService;
        this.goodsService = goodsService;
        this.shopperService = shopperService;
        this.regionService = regionService;
        this.couponService = couponService;
        this.couponLogService = couponLogService;
        this.orderInfoMapper = orderInfoMapper;
    }

    @Resource
    private GaoDeClient gaoDeClient;

    @Override
    public Page<OrderInfo> queryPage(CommonPageReq<OrderQueryParam> queryPageParam) {
        OrderQueryParam queryParam = queryPageParam.getQueryParam();

        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if (queryParam != null) {
            if (StringUtils.hasLength(queryParam.getUserName())) {
                Member member = memberService.queryByPhone(queryParam.getUserName());
                if (member == null) {
                    return new Page<>();
                }
                wrapper.lambda().eq(OrderInfo::getUserId, member.getUserId());
            }
            if (StringUtils.hasLength(queryParam.getOrderSn())) {
                wrapper.lambda().like(OrderInfo::getOrderSn, queryParam.getOrderSn());
            }
            if (StringUtils.hasLength(queryParam.getUserId())) {
                wrapper.lambda().eq(OrderInfo::getUserId, queryParam.getUserId());
            }
            if (StringUtils.hasLength(queryParam.getTel())) {
                wrapper.lambda().like(OrderInfo::getTel, queryParam.getTel());
            }
            if (StringUtils.hasLength(queryParam.getConsignee())) {
                wrapper.lambda().like(OrderInfo::getConsignee, queryParam.getConsignee());
            }
            if (StringUtils.hasLength(queryParam.getCouponId())) {
                wrapper.lambda().like(OrderInfo::getCouponId, queryParam.getCouponId());
            }
            if (queryParam.getShippingDate() != null) {
                wrapper.lambda().eq(OrderInfo::getShippingDay, queryParam.getShippingDate());
            }
            if (queryParam.getOrderStatus() != null) {
                wrapper.lambda().ge(OrderInfo::getOrderStatus, queryParam.getOrderStatus());
            } else {
                wrapper.lambda().ge(OrderInfo::getOrderStatus, 2);
            }
            if (queryParam.getShipQuery() != null && queryParam.getShipQuery()) {
                wrapper.lambda().in(OrderInfo::getOrderStatus, 2,3,4,5);
            }
            if (queryParam.getShippingHour() != null){
                wrapper.lambda().eq(OrderInfo::getShippingHour, queryParam.getShippingHour());
            }
            if (queryParam.getShopperId() != null){
                wrapper.lambda().eq(OrderInfo::getShippingId, queryParam.getShopperId());
            }
            if (StringUtils.hasLength(queryParam.getDistrict())){
                wrapper.lambda().eq(OrderInfo::getDistrict, queryParam.getDistrict());
            }
            if (StringUtils.hasLength(queryParam.getAddStartDate()) && StringUtils.hasLength(queryParam.getAddEndDate())) {
                LocalDateTime queryEndDate = DateUtil.parseLocalDateTime(queryParam.getAddEndDate(), "yyyy-MM-dd").plusDays(1);
                String queryEndDateStr = DateUtil.format(queryEndDate, "yyyy-MM-dd");
                long startDate = DateUtil.parse(queryParam.getAddStartDate() + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();
                long endDate = DateUtil.parse(queryEndDateStr + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();

                wrapper.lambda().ge(OrderInfo::getAddTime, startDate / 1000);
                wrapper.lambda().lt(OrderInfo::getAddTime, endDate / 1000);
            }
        }
        wrapper.lambda().orderByDesc(OrderInfo::getAddTime);

        Page<OrderInfo> pageInfo = new Page<>(queryPageParam.getPageNo(), queryPageParam.getPageSize());
        page(pageInfo, wrapper);

        buildRecords(pageInfo.getRecords());

        return pageInfo;
    }

    private void buildRecords(List<OrderInfo> records) {
        if (!CollectionUtils.isEmpty(records)) {
            Set<Integer> memberIds = new HashSet<>();
            Set<Integer> orderIds = new HashSet<>();
            Set<String> couponIds = new HashSet<>();
            Set<Integer> regionIds = new HashSet<>();
            records.forEach(orderInfo -> {
                memberIds.add(orderInfo.getUserId());
                orderIds.add(orderInfo.getOrderId());
                regionIds.add(orderInfo.getProvince());
                regionIds.add(orderInfo.getCity());
                regionIds.add(orderInfo.getDistrict());
                couponIds.add(orderInfo.getCouponId());
            });
            List<OrderGoods> orderGoods = orderGoodService.listByOrderIds(orderIds);
            Set<Integer> goodIds = orderGoods.stream().map(OrderGoods::getGoodsId).collect(Collectors.toSet());
            List<Goods> goodsList = goodsService.listByIds(goodIds);
            orderGoods.forEach(orderGood -> goodsList.forEach(good -> {
                if (orderGood.getGoodsId().equals(good.getGoodsId())) {
                    orderGood.setGoodsThumb(good.getGoodsThumb());
                }
            }));
            Map<Integer, List<OrderGoods>> orderGoodMap = orderGoods.stream().collect(Collectors.groupingBy(OrderGoods::getOrderId));
            List<Member> members = memberService.listByIds(memberIds);

            List<OrderInfo> orderInfoList = listByMemberIds(memberIds);
            Map<Integer, List<OrderInfo>> memberOrderMap = orderInfoList.stream().collect(Collectors.groupingBy(OrderInfo::getUserId));

            List<Region> regionList = regionService.listByIds(regionIds);
            Map<Integer, Region> regionMap = regionList.stream().collect(Collectors.toMap(Region::getRegionId, region -> region));

            List<Coupon> coupons = new ArrayList<>();
            if (!CollectionUtils.isEmpty(couponIds)) {
                coupons = couponService.listByCouponCodes(couponIds);
            }

            List<Coupon> finalCoupons = coupons;
            records.forEach(orderInfo -> {
                String addTimeText = DateUtils.formatLongTime(orderInfo.getAddTime() * 1000);
                if (orderInfo.getShippingDay() != null) {
                    String shippingDateText = DateTimeFormatterConstants.DATE_FORMAT.format(orderInfo.getShippingDay());
                    orderInfo.setShippingText(shippingDateText + "【" + orderInfo.getShippingHour() + ":00】");
                }
                orderInfo.setAddTimeText(addTimeText);
                List<OrderGoods> orderGoodsList = orderGoodMap.getOrDefault(orderInfo.getOrderId(), new ArrayList<>());
                orderGoodsList.forEach(orderGood -> {
                    String goodsName = orderGood.getGoodsName().replaceAll("\\(草莓啵啵口味\\)","");
                    goodsName = goodsName.replaceAll("\\(巧克力口味\\)","");
                    orderGood.setGoodsName(goodsName);
                });
                orderInfo.setGoodList(orderGoodsList);
                orderInfo.setBuyOrderNumber(memberOrderMap.getOrDefault(orderInfo.getUserId(), new ArrayList<>()).size());
                orderInfo.setIsFirst(memberOrderMap.getOrDefault(orderInfo.getUserId(), new ArrayList<>()).size() == 1);
                if(orderInfo.getProvince() != null && !StringUtils.hasLength(orderInfo.getProvinceName())){
                    Region region = regionMap.get(orderInfo.getProvince());
                    if(region != null){
                        orderInfo.setProvinceName(region.getRegionName());
                    }
                }
                if(orderInfo.getCity() != null && !StringUtils.hasLength(orderInfo.getCityName())){
                    Region region = regionMap.get(orderInfo.getCity());
                    if(region != null){
                        orderInfo.setCityName(region.getRegionName());
                    }
                }
                if(orderInfo.getDistrict() != null && !StringUtils.hasLength(orderInfo.getDistrictName())){
                    Region region = regionMap.get(orderInfo.getDistrict());
                    if(region != null){
                        orderInfo.setDistrictName(region.getRegionName());
                    }
                }
                members.forEach(member -> {
                    if (orderInfo.getUserId().equals(member.getUserId())) {
                        orderInfo.setSubmitUserPhone(member.getUserName());
                        orderInfo.setUserName(member.getUserName());
                    }
                });
                if (StringUtils.hasLength(orderInfo.getCouponId())) {
                    finalCoupons.forEach(coupon -> {
                        if (coupon.getCouponId().equals(orderInfo.getCouponId())) {
                            orderInfo.setCouponName(coupon.getName());
                        }
                    });
                }
                buildLongitudeAndLatitude(orderInfo);
            });
        }
    }

    /**
     * 根据收货地址调用高德地图api获取经纬度
     */
    private void buildLongitudeAndLatitude(OrderInfo orderInfo) {
        if(!StringUtils.hasLength(orderInfo.getLocation())){
            GaoDeResponse gaoDeResponse = gaoDeClient.getLocation("南京",orderInfo.getProvinceName() + orderInfo.getCityName() + orderInfo.getDistrictName() + orderInfo.getAddress());
            if(gaoDeResponse != null && gaoDeResponse.getStatus() == 1){
                if(!CollectionUtils.isEmpty(gaoDeResponse.getGeocodes())){
                    gaoDeResponse.getGeocodes().forEach(geocode -> {
                        orderInfo.setLocation(geocode.getLocation());
                    });
                    CompletableFuture.runAsync(() -> updateById(orderInfo));
                }
            }
        }
    }

    private void buildSaveLongitudeAndLatitude(OrderInfo orderInfo) {
        GaoDeResponse gaoDeResponse = gaoDeClient.getLocation("南京",orderInfo.getProvinceName() + orderInfo.getCityName() + orderInfo.getDistrictName() + orderInfo.getAddress());
        if(gaoDeResponse != null && gaoDeResponse.getStatus() == 1){
            if(!CollectionUtils.isEmpty(gaoDeResponse.getGeocodes())){
                gaoDeResponse.getGeocodes().forEach(geocode -> {
                    orderInfo.setLocation(geocode.getLocation());
                });
                CompletableFuture.runAsync(() -> updateById(orderInfo));
            }
        }
    }

    public List<OrderInfo> listByMemberIds(Collection<Integer> memberIds) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(OrderInfo::getUserId, memberIds);
        wrapper.lambda().ge(OrderInfo::getOrderStatus,2);
        return list(wrapper);
    }

    @Override
    public AnalysisData analysis(OrderQueryParam queryParam) {
        AnalysisData analysisData = new AnalysisData();
        Map<String, Long> hourGroupSaleData = new HashMap<>();
        Map<String, Long> addTimeGroupSaleData = new HashMap<>();
        analysisData.setHourGroupSaleData(hourGroupSaleData);
        analysisData.setAddTimeGroupSaleData(addTimeGroupSaleData);
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if (StringUtils.hasLength(queryParam.getAddStartDate()) && StringUtils.hasLength(queryParam.getAddEndDate())) {
            LocalDateTime queryEndDate = DateUtil.parseLocalDateTime(queryParam.getAddEndDate(), "yyyy-MM-dd").plusDays(1);
            String queryEndDateStr = DateUtil.format(queryEndDate, "yyyy-MM-dd");
            long startDate = DateUtil.parse(queryParam.getAddStartDate() + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();
            long endDate = DateUtil.parse(queryEndDateStr + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();

            wrapper.lambda().ge(OrderInfo::getAddTime, startDate / 1000);
            wrapper.lambda().lt(OrderInfo::getAddTime, endDate / 1000);
        }
        wrapper.lambda().in(OrderInfo::getOrderStatus, 2, 3, 4, 5);
        List<OrderInfo> orderList = list(wrapper);

        if (!CollectionUtils.isEmpty(orderList)) {
            List<Integer> orderIds = orderList.stream().map(OrderInfo::getOrderId).collect(Collectors.toList());
            List<OrderGoods> orderGoodList = orderGoodService.listByOrderIds(orderIds);
            orderGoodList.removeIf(orderGood -> orderGood.getGoodsSn().startsWith("P25") || orderGood.getGoodsSn().startsWith("P24"));
            Map<Integer, List<OrderGoods>> orderGoodMap = orderGoodList.stream().collect(Collectors.groupingBy(OrderGoods::getGoodsId));
            QueryWrapper<Goods> goodsQueryWrapper = new QueryWrapper<>();
            goodsQueryWrapper.lambda().in(Goods::getGoodsId, orderGoodMap.keySet());
            goodsQueryWrapper.lambda().in(Goods::getCatId, 5,26);
            goodsQueryWrapper.lambda().eq(Goods::getBelongTo, "103");
            List<Goods> goodsList = goodsService.list(goodsQueryWrapper);
            Map<Integer, Goods> goodMap = goodsList.stream().collect(Collectors.toMap(Goods::getGoodsId, g -> g));

            Map<String, List<GoodAttrCountData>> orderGoodCountMap = new HashMap<>();
            orderGoodMap.forEach((goodId, goodList) -> {
                Goods good = goodMap.get(goodId);
                if (good != null) {
                    Map<String, List<OrderGoods>> orderGoodAttrMap = goodList.stream().collect(Collectors.groupingBy(OrderGoods::getGoodsAttr));
                    List<GoodAttrCountData> goodAttrCountDataList = new ArrayList<>();
                    orderGoodAttrMap.forEach((goodDesc, goodAttrList) -> {
                        GoodAttrCountData goodAttrCountData = new GoodAttrCountData();
                        goodAttrCountData.setAttrName(goodDesc);
                        goodAttrCountData.setCount((long) goodAttrList.size());
                        goodAttrCountDataList.add(goodAttrCountData);
                    });
                    orderGoodCountMap.put(good.getGoodsName(),goodAttrCountDataList);
                }
            });

            Map<String, List<OrderInfo>> hourOrderMap = orderList.stream().filter(item -> item.getShippingHour() != null && item.getShippingHour() > 0).collect(Collectors.groupingBy(item -> item.getShippingHour() + ":00" + "~" + (item.getShippingHour() + 1) + ":00"));
            Map<String, List<OrderInfo>> addTimeOrderMap = orderList.stream().collect(Collectors.groupingBy(item -> DateUtils.formatHourByLongTime(item.getAddTime() * 1000) + ":00"));

            Map<Integer, List<OrderInfo>> areaOrderMap = orderList.stream().filter(item -> item.getCity() == 320100).collect(Collectors.groupingBy(OrderInfo::getDistrict));
            Map<String, Long> areaOrderCountMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(areaOrderMap)) {
                List<Region> regionList = regionService.listByIds(areaOrderMap.keySet());
                Map<Integer, Region> regionMap = regionList.stream().collect(Collectors.toMap(Region::getRegionId, r -> r));
                areaOrderMap.forEach((regionId, areaOrderList) -> {
                    Region region = regionMap.get(regionId);
                    if (region != null) {
                        areaOrderCountMap.put(region.getRegionName(), (long) areaOrderList.size());
                    }
                });
            }

            hourOrderMap.forEach((hour, orderInfoList) -> hourGroupSaleData.put(hour, (long) orderInfoList.size()));
            addTimeOrderMap.forEach((hour, orderInfoList) -> addTimeGroupSaleData.put(hour, (long) orderInfoList.size()));
            analysisData.setAreaGroupSaleData(areaOrderCountMap);
            analysisData.setOrderGoodCountData(orderGoodCountMap);
        }

        return analysisData;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean onSave(OrderInfo orderInfo) {
        if (orderInfo.getPayId().equals(104)) {
            orderInfo.setPayName("货到付款");
            orderInfo.setFromAd(102);
            orderInfo.setReferer("管理员");
        } else if (orderInfo.getPayId().equals(106)) {
            orderInfo.setPayName("线下已转账");
            orderInfo.setFromAd(102);
            orderInfo.setReferer("管理员");
        }
        if (orderInfo.getOrderId() == null) {
            Member member = memberService.queryByPhone(orderInfo.getSubmitUserPhone());
            if (member != null) {
                orderInfo.setUserId(member.getUserId());
            }
            orderInfo.setOrderStatus(2);
            orderInfo.setPayStatus(0);
            orderInfo.setAddTime(System.currentTimeMillis() / 1000);
            String orderSn = RandomUtil.getOrderCode();
            log.info("订单号：{}", orderSn);
            orderInfo.setOrderSn(orderSn);
            AtomicReference<BigDecimal> goodsAmount = new AtomicReference<>(new BigDecimal(0));
            AtomicReference<BigDecimal> goodsBartletAmount = new AtomicReference<>(new BigDecimal(0));
            if (!CollectionUtils.isEmpty(orderInfo.getGoodList())) {
                orderInfo.getGoodList().forEach(item -> {
                    BigDecimal goodNum = new BigDecimal(item.getGoodsNumber());
                    goodsAmount.set(goodsAmount.get().add(item.getGoodsPrice().multiply(goodNum)));
                    goodsBartletAmount.set(goodsBartletAmount.get().add(item.getMarketPrice().multiply(goodNum)));
                });
            }
            orderInfo.setGoodsAmount(goodsAmount.get());
            if (StringUtils.hasLength(orderInfo.getCouponId())) {
                Coupon coupon = couponService.getByCouponId(orderInfo.getCouponId());
                if (coupon == null) {
                    throw new CommonException("优惠券不存在，请确认再下单");
                }
                couponLogService.addLog(orderInfo.getUserId(), orderInfo.getCouponId(), orderInfo.getOrderId());
                if ("金额".equals(coupon.getType())) {
                    BigDecimal couponAmount = new BigDecimal(coupon.getValue());
                    BigDecimal payMoney = goodsAmount.get().subtract(couponAmount);
                    if (payMoney.compareTo(BigDecimal.ZERO) < 0) {
                        payMoney = BigDecimal.ZERO;
                        orderInfo.setDiscount(goodsAmount.get());
                    } else {
                        orderInfo.setDiscount(couponAmount);
                    }
                    orderInfo.setOrderAmount(payMoney.add(orderInfo.getShippingFee()));
                    orderInfo.setMoneyPaid(payMoney.add(orderInfo.getShippingFee()));
                }
            }
        }
        saveOrUpdate(orderInfo);

        orderInfo.getGoodList().forEach(item -> {
            if (item.getRecId() == null) {
                item.setOrderId(orderInfo.getOrderId());
            }
        });
        orderGoodService.saveOrUpdateBatch(orderInfo.getGoodList());

        buildSaveLongitudeAndLatitude(orderInfo);

        return true;
    }

    @Override
    public List<OrderGoods> queryProductMakeGoods(MakeQueryParam makeQueryParam) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if (StringUtils.hasLength(makeQueryParam.getShippingDate())) {
            wrapper.lambda().eq(OrderInfo::getShippingDay, makeQueryParam.getShippingDate());
        } else {
            LocalDate now = LocalDate.now();
            String nowShippingDate = DateTimeFormatterConstants.DATE_FORMAT.format(now);
            wrapper.lambda().eq(OrderInfo::getShippingDay, nowShippingDate);
        }
        wrapper.lambda().in(OrderInfo::getOrderStatus, 2, 3, 4, 5);
        List<OrderInfo> orderInfoList = list(wrapper);
        if (CollectionUtils.isEmpty(orderInfoList)) {
            return new ArrayList<>();
        }
        List<Integer> orderIds = orderInfoList.stream().map(OrderInfo::getOrderId).collect(Collectors.toList());
        QueryWrapper<OrderGoods> goodsQueryWrapper = new QueryWrapper<>();
        goodsQueryWrapper.lambda().in(OrderGoods::getOrderId, orderIds);
        List<OrderGoods> orderGoodList = orderGoodService.list(goodsQueryWrapper);
        orderGoodList.removeIf(orderGood -> orderGood.getGoodsSn().startsWith("P22") || orderGood.getGoodsSn().startsWith("P25") || orderGood.getGoodsSn().startsWith("P24"));
        buildMakeGoods(orderGoodList, orderInfoList);
        return orderGoodList;
    }

    @Override
    public List<OrderInfo> selectMakeGoods(Integer startHour, Integer endHour) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(OrderInfo::getOrderStatus, 2, 3, 4, 5);
        wrapper.lambda().ge(OrderInfo::getShippingHour, startHour);
        wrapper.lambda().lt(OrderInfo::getShippingHour, endHour);
        LocalDate now = LocalDate.now();
        String nowShippingDate = DateTimeFormatterConstants.DATE_FORMAT.format(now);
        wrapper.lambda().eq(OrderInfo::getShippingDay, nowShippingDate);
        return list(wrapper);
    }

    @Override
    public boolean updateMakeGood(Integer orderId, String goodsSn, String goodsAttr) {
        QueryWrapper<OrderGoods> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(OrderGoods::getOrderId, orderId);
        wrapper.lambda().eq(OrderGoods::getGoodsId, goodsSn);
        wrapper.lambda().eq(OrderGoods::getGoodsAttr, goodsAttr);
        List<OrderGoods> orderGoods = orderGoodService.list(wrapper);
        if(!CollectionUtils.isEmpty(orderGoods)){
            orderGoods.forEach(item -> {
                item.setSendNumber(item.getGoodsNumber().intValue());
            });
            orderGoodService.updateBatchById(orderGoods);
        }
        return true;
    }

    @Override
    public List<StatisticModel> salesStatisticsByDateRange(OrderQueryParam queryParam) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if (StringUtils.hasLength(queryParam.getAddStartDate()) && StringUtils.hasLength(queryParam.getAddEndDate())) {
            LocalDateTime queryEndDate = DateUtil.parseLocalDateTime(queryParam.getAddEndDate(), "yyyy-MM-dd").plusDays(1);
            String queryEndDateStr = DateUtil.format(queryEndDate, "yyyy-MM-dd");
            long startDate = DateUtil.parse(queryParam.getAddStartDate() + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();
            long endDate = DateUtil.parse(queryEndDateStr + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();

            wrapper.lambda().ge(OrderInfo::getAddTime, startDate / 1000);
            wrapper.lambda().lt(OrderInfo::getAddTime, endDate / 1000);
        }
        wrapper.lambda().in(OrderInfo::getOrderStatus, 2, 3, 4, 5);
        List<OrderInfo> orderList = list(wrapper);

        Map<String, List<OrderInfo>> addDateOrderMap = orderList.stream().collect(Collectors.groupingBy(item -> DateUtils.formatDateByLongTime(item.getAddTime() * 1000)));
        List<StatisticModel> statisticModelList = new ArrayList<>();
        addDateOrderMap.forEach((day, orderInfoList) -> {
            long saleTotal = orderInfoList.size();
            AtomicReference<BigDecimal> totalSaleAmount = new AtomicReference<>(BigDecimal.ZERO);
            orderInfoList.forEach(orderInfo -> {
                totalSaleAmount.set(totalSaleAmount.get().add(orderInfo.getMoneyPaid()));
            });
            StatisticModel statisticModel = new StatisticModel();
            statisticModel.setTitle(day);
            statisticModel.setTotal(saleTotal);
            statisticModel.setTotalSaleAmount(totalSaleAmount.get());
            statisticModelList.add(statisticModel);
        });
        return statisticModelList.stream().sorted(Comparator.comparing(StatisticModel::getTitle)).collect(Collectors.toList());
    }

    @Override
    public List<StatisticModel> salesStatisticsByDay(OrderQueryParam queryParam) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if (StringUtils.hasLength(queryParam.getAddStartDate())) {
            long startDate = DateUtil.parse(queryParam.getAddStartDate() + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();

            LocalDateTime queryEndDate = DateUtil.parseLocalDateTime(queryParam.getAddStartDate() + " 00:00:00", "yyyy-MM-dd HH:mm:ss").plusDays(1);
            String queryEndDateStr = DateUtil.format(queryEndDate, "yyyy-MM-dd");
            long endDate = DateUtil.parse(queryEndDateStr + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();

            wrapper.lambda().ge(OrderInfo::getAddTime, startDate / 1000);
            wrapper.lambda().lt(OrderInfo::getAddTime, endDate / 1000);
        }
        wrapper.lambda().in(OrderInfo::getOrderStatus, 2, 3, 4, 5);
        List<OrderInfo> orderList = list(wrapper);

        Map<String, List<OrderInfo>> addHourOrderMap = orderList.stream().collect(Collectors.groupingBy(item -> DateUtils.formatHourByLongTime(item.getAddTime() * 1000) + ":00"));

        List<StatisticModel> statisticModelList = new ArrayList<>();
        addHourOrderMap.forEach((hour, orderInfoList) -> {
            long saleTotal = orderInfoList.size();
            AtomicReference<BigDecimal> totalSaleAmount = new AtomicReference<>(BigDecimal.ZERO);
            orderInfoList.forEach(orderInfo -> {
                totalSaleAmount.set(totalSaleAmount.get().add(orderInfo.getMoneyPaid()));
            });
            StatisticModel statisticModel = new StatisticModel();
            statisticModel.setTitle(hour);
            statisticModel.setTotal(saleTotal);
            statisticModel.setTotalSaleAmount(totalSaleAmount.get());
            statisticModelList.add(statisticModel);
        });
        return statisticModelList.stream().sorted(Comparator.comparing(StatisticModel::getTitle)).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean allocation(DisShippingParam disShippingParam) {
        Shopper shopper = shopperService.getById(disShippingParam.getShippingId());
        if (shopper == null) {
            throw new CommonException("未找到配送员");
        }
        List<OrderInfo> orderInfos = listByIds(disShippingParam.getOrderIds());
        if (CollectionUtils.isEmpty(orderInfos)) {
            throw new CommonException("订单信息未找到");
        }
        orderInfos.forEach(orderInfo -> {
            orderInfo.setShippingId(disShippingParam.getShippingId());
            orderInfo.setShippingName(shopper.getRealname());
        });
        return updateBatchById(orderInfos);
    }

    @Override
    public List<Map> summaryForChart(ChartParam chartParam) {
        return orderInfoMapper.summaryForChart(chartParam);
    }

    @Override
    public List<OrderInfo> queryExportList(OrderQueryParam queryParam) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        if (StringUtils.hasLength(queryParam.getAddStartDate()) && StringUtils.hasLength(queryParam.getAddEndDate())) {
            LocalDateTime queryEndDate = DateUtil.parseLocalDateTime(queryParam.getAddEndDate(), "yyyy-MM-dd").plusDays(1);
            String queryEndDateStr = DateUtil.format(queryEndDate, "yyyy-MM-dd");
            long startDate = DateUtil.parse(queryParam.getAddStartDate() + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();
            long endDate = DateUtil.parse(queryEndDateStr + " 00:00:00", "yyyy-MM-dd HH:mm:ss").getTime();

            wrapper.lambda().ge(OrderInfo::getAddTime, startDate / 1000);
            wrapper.lambda().lt(OrderInfo::getAddTime, endDate / 1000);
        }
        if (StringUtils.hasLength(queryParam.getShippingDate())) {
            wrapper.lambda().eq(OrderInfo::getShippingDay, queryParam.getShippingDate());
        }
        wrapper.lambda().ge(OrderInfo::getOrderStatus, 2);
        List<OrderInfo> orderInfoList = list(wrapper);
        buildRecords(orderInfoList);
        return orderInfoList;
    }

    private void buildMakeGoods(List<OrderGoods> orderGoodList, List<OrderInfo> orderInfoList) {
        if (!CollectionUtils.isEmpty(orderGoodList)) {
            Map<Integer, OrderInfo> orderInfoMap = orderInfoList.stream().collect(Collectors.toMap(OrderInfo::getOrderId, orderInfo -> orderInfo));
            orderGoodList.forEach(orderGoods -> {
                OrderInfo order = orderInfoMap.getOrDefault(orderGoods.getOrderId(), null);
                if (order != null) {
                    orderGoods.setShippingHour(order.getShippingHour());
                }
            });
        }
    }
}
